package com.yichuang.wuziqi.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

import com.yichuang.wuziqi.R;
import com.yichuang.wuziqi.game.LocalGame;
import com.yichuang.wuziqi.game.Recorder;
import com.yichuang.wuziqi.player.Playable;
import com.yichuang.wuziqi.player.Player;
import com.yichuang.wuziqi.tool.AIAlgorithm1;
import com.yichuang.wuziqi.tool.GameTools;

import java.util.ArrayList;

/**
 * Created by xcm on 17-11-26.
 */

public class BoardPanel extends View implements Recorder {

    private static final String TAG = "xcm";

    private int panelWidth;
    private float lineWidth;

    private Paint paint = new Paint();
    private Paint textPaint = new Paint();
    private Bitmap whitePieceBitMap;
    private Bitmap blackPieceBitMap;

    //棋子和行高的比例
    private float ratioPieceSize = 0.75f;

    private ArrayList<Point> whitePositions = new ArrayList<>();
    private ArrayList<Point> blackPositions = new ArrayList<>();
    private int[][] positionValue = new int[LocalGame.MAX_LINE][LocalGame.MAX_LINE];

    private volatile boolean isDrooped;
    private Point currentPosition;
    private Point currentDropPoint;
    private boolean isWhiteWinner;
    private boolean isGameOver;

    private final Object lock = new Object();

    public BoardPanel(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        setBackgroundColor(0xaaccffff);
        initView();
    }

    private void initView() {
        paint.setColor(0x88000000);
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setStyle(Paint.Style.STROKE);

        whitePieceBitMap = BitmapFactory.decodeResource(getResources(), R.drawable.white);
        blackPieceBitMap = BitmapFactory.decodeResource(getResources(), R.drawable.black);
    }

    public void reset() {
        synchronized (lock) {
            whitePositions.clear();
            blackPositions.clear();
        }
        positionValue = new int[LocalGame.MAX_LINE][LocalGame.MAX_LINE];
        isDrooped = false;
        isWhiteWinner = false;
        isGameOver = false;
        invalidate();
    }

    public Point getDrop() {
        while (!isDrooped) {

        }
        isDrooped = false;
        return currentDropPoint;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);

        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int width = Math.min(widthSize, heightSize);

        if (widthMode == MeasureSpec.UNSPECIFIED) {
            width = heightSize;
        } else if (heightMode == MeasureSpec.UNSPECIFIED) {
            width = widthSize;
        }

        setMeasuredDimension(width, width);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        panelWidth = w;
        lineWidth = panelWidth * 1.0f / LocalGame.MAX_LINE;

        //棋盘大小变化时，棋子的大小也进行相应的改变
        int pieceWidth = (int) (lineWidth * ratioPieceSize);
        whitePieceBitMap = Bitmap.createScaledBitmap(whitePieceBitMap, pieceWidth, pieceWidth, false);
        blackPieceBitMap = Bitmap.createScaledBitmap(blackPieceBitMap, pieceWidth, pieceWidth, false);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawBoard(canvas);
        drawPieces(canvas);
        drawValues(canvas);
        if (isGameOver) {
            String text = isWhiteWinner ? "白棋胜利" : "黑棋胜利";
            Toast.makeText(getContext(), text, Toast.LENGTH_SHORT).show();
            Paint paint = new Paint();
            paint.setColor(0xFFFF0000);
            paint.setAntiAlias(true);
            paint.setTextSize(60);
            Rect rect = new Rect();
            //返回包围整个字符串的最小的一个Rect区域
            paint.getTextBounds(text, 0, 1, rect);
            int textWidth = rect.width();
            int textHeight = rect.height();
            canvas.drawText(text, (getWidth() - textWidth) / 2, (getHeight() - textHeight) / 2, paint);
        }
    }

    private void drawValues(Canvas canvas) {
        Paint paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
        paint.setColor(0xcc0000ff);
        paint.setTextSize(20.0f);
        paint.setStrokeWidth(1.0f);
        for (int i = 0; i < LocalGame.MAX_LINE; i++) {
            for (int j = 0; j < LocalGame.MAX_LINE; j++) {
                if (positionValue[i][j] == 0) {
                    continue;
                }
                float px = (float) (0.5 * lineWidth + i * lineWidth) - 5;
                float py = (float) (0.5 * lineWidth + j * lineWidth);
                canvas.drawText(positionValue[i][j] + "", px, py, paint);
            }
        }
    }

    //called from child-thread
    @Override
    public void record(int playerSide, Point point) {
        synchronized (lock) {
            Log.d(TAG, "record: " + point);
            currentPosition = point;
            if (playerSide == Playable.WHITE_SIDE) {
                whitePositions.add(point);
            } else {
                blackPositions.add(point);
            }
            evaluate();
            postInvalidate();
        }
    }

    @Override
    public boolean checkGameOver() {
        synchronized (lock) {
            boolean whiteWin = GameTools.checkFiveInLine(whitePositions);
            boolean blackWin = GameTools.checkFiveInLine(blackPositions);
            if (whiteWin || blackWin) {
                isGameOver = true;
                isWhiteWinner = whiteWin;
            }
            return isGameOver;
        }
    }

    @Override
    public void takeBack(int playerSide) {
        synchronized (lock) {
            if (playerSide == Player.WHITE_SIDE) {
                whitePositions.remove(whitePositions.size() - 1);
            } else {
                blackPositions.remove(blackPositions.size() - 1);
            }
        }
        isGameOver = false;
        evaluate();
        postInvalidate();
    }

    private void drawPieces(Canvas canvas) {
        textPaint.setColor(0xFFFF0000);
        textPaint.setAntiAlias(true);
        textPaint.setStrokeWidth(5.0f);
        textPaint.setStyle(Paint.Style.STROKE);
        textPaint.setPathEffect(new DashPathEffect(new float[]{10, 10}, 0));
        for (int i = 0, n = whitePositions.size(); i < n; i++) {
            Point whitePoint = whitePositions.get(i);
            float pieceLeft = (whitePoint.x + (1 - ratioPieceSize) / 2) * lineWidth;
            float pieceTop = (whitePoint.y + (1 - ratioPieceSize) / 2) * lineWidth;
            canvas.drawBitmap(whitePieceBitMap, pieceLeft, pieceTop, null);
            if (whitePoint.equals(currentPosition)) {
                canvas.drawRect(pieceLeft - 5, pieceTop - 5,
                        pieceLeft + whitePieceBitMap.getWidth() + 5,
                        pieceTop + whitePieceBitMap.getHeight() + 5, paint);
            }
        }
        for (int i = 0, n = blackPositions.size(); i < n; i++) {
            Point blackPoint = blackPositions.get(i);
            float pieceLeft = (blackPoint.x + (1 - ratioPieceSize) / 2) * lineWidth;
            float pieceTop = (blackPoint.y + (1 - ratioPieceSize) / 2) * lineWidth;
            canvas.drawBitmap(blackPieceBitMap, pieceLeft, pieceTop, null);
            if (blackPoint.equals(currentPosition)) {
                canvas.drawRect(pieceLeft - 5, pieceTop - 5,
                        pieceLeft + whitePieceBitMap.getWidth() + 5,
                        pieceTop + whitePieceBitMap.getHeight() + 5, paint);
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        int action = event.getAction();
        if (action == MotionEvent.ACTION_UP) {
            int x = (int) event.getX();
            int y = (int) event.getY();

            Point p = getValidPoint(x, y);
            if (whitePositions.contains(p) || blackPositions.contains(p)) {
                return false;
            }

            if (p.x >= LocalGame.MAX_LINE || p.y >= LocalGame.MAX_LINE || p.x < 0 || p.y < 0) {
                return false;
            }

            Log.d(TAG, "onTouchEvent: " + p);
            currentDropPoint = p;
            isDrooped = true;
            return true;
        }

        return true;
    }

    /**
     * 给出位置价值参考
     */
    private void evaluate() {
        positionValue = new int[LocalGame.MAX_LINE][LocalGame.MAX_LINE];
        Point p;
        for (int i = 0; i < LocalGame.MAX_LINE; i++) {
            for (int j = 0; j < LocalGame.MAX_LINE; j++) {
                p = new Point(i, j);
                if (!whitePositions.contains(p) && !blackPositions.contains(p)) {
                    positionValue[i][j] = AIAlgorithm1.EvaluatePosition(p, whitePositions, blackPositions);
                }
            }
        }
    }

    private Point getValidPoint(int x, int y) {
        return new Point((int) (x / lineWidth), (int) (y / lineWidth));
    }

    private void drawBoard(Canvas canvas) {
        int w = panelWidth;
        float lineHeight = lineWidth;
        for (int i = 0; i < LocalGame.MAX_LINE; i++) {
            int startX = (int) (lineHeight / 2);
            int endX = (int) (w - lineHeight / 2);
            int y = (int) ((0.5 + i) * lineHeight);
            //画横线
            canvas.drawLine(startX, y, endX, y, paint);
            //画竖线
            canvas.drawLine(y, startX, y, endX, paint);
        }
    }

    private static final String INSTANCE = "instance";
    private static final String INSTANCE_GAME_OVER = "instance_game_over";
    private static final String INSTANCE_WHITE_POSITIONS = "instance_white_positions";
    private static final String INSTANCE_BLACK_POSITIONS = "instance_black_positions";

    @Nullable
    @Override
    protected Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        bundle.putParcelable(INSTANCE, super.onSaveInstanceState());
        bundle.putBoolean(INSTANCE_GAME_OVER, isGameOver);
        bundle.putParcelableArrayList(INSTANCE_WHITE_POSITIONS, whitePositions);
        bundle.putParcelableArrayList(INSTANCE_BLACK_POSITIONS, blackPositions);
        return bundle;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (state instanceof Bundle) {
            Bundle bundle = (Bundle) state;
            isGameOver = bundle.getBoolean(INSTANCE_GAME_OVER);
            whitePositions = bundle.getParcelableArrayList(INSTANCE_WHITE_POSITIONS);
            blackPositions = bundle.getParcelableArrayList(INSTANCE_BLACK_POSITIONS);
            super.onRestoreInstanceState(bundle.getParcelable(INSTANCE));
            return;
        }
        super.onRestoreInstanceState(state);
    }

}
